home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1983 The Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley. The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
- #ifndef lint
- char copyright[] =
- "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
- All rights reserved.\n";
- #endif /* not lint */
-
- #ifndef lint
- static char sccsid[] = "@(#)tip.c 5.8 (Berkeley) 9/2/88";
- #endif /* not lint */
-
- /*
- * tip - UNIX link to other systems
- * tip [-psv] [-speed] system-name [data]
- * or
- * cu phone-number [-s speed] [-l line] [-a acu]
- */
- #include "tip.h"
-
- /*
- * Baud rate mapping table
- */
- int bauds[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600,
- 1200, 1800, 2400, 4800, 9600, 19200, 38400, -1
- };
-
- int page;
- int disc = OTTYDISC; /* tip normally runs this way */
- sigfunc_t intprompt();
- sigfunc_t timeout();
- sigfunc_t cleanup();
- char *login();
- char *sname();
- char PNbuf[256]; /* This limits the size of a number */
-
- main(argc, argv)
- char *argv[];
- {
- int uuid;
- char *system = NOSTR;
- char *data = NOSTR;
- register int i;
- register char *p;
- char sbuf[12];
-
- uid = getuid();
- gid = getgid();
- euid = geteuid(); /* should be root */
- egid = getegid();
- uuid = getuucpuid();
-
- if (equal(sname(argv[0]), "cu")) {
- setreuid(uid, uuid);
- cumode = 1;
- cumain(argc, argv);
- goto cucommon;
- }
-
- if (argc < 2) {
- fprintf(stderr, "usage: tip [-psv] [-speed] [system-name] [data]\n");
- exit(1);
- }
-
- for (; argc > 1; argv++, argc--) {
- if (argv[1][0] != '-') {
- if (system)
- data = argv[1];
- else
- system = argv[1];
- }
- else switch (argv[1][1]) {
-
- case 'p':
- page++;
- break;
- case 's':
- slip++;
- break;
- case 'v':
- vflag++;
- break;
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- BR = atoi(&argv[1][1]);
- break;
-
- default:
- fprintf(stderr, "tip: %s, unknown option\n", argv[1]);
- break;
- }
- }
- if (!isatty(0) && !slip && !page) {
- fprintf(stderr, "tip: warning: input is not a tty\n");
- }
- if (slip) {
- setreuid(euid, uuid);
- uid = 0;
- } else {
- setreuid(uid, uuid);
- }
- euid = uuid;
-
- if (system == NOSTR)
- goto notnumber;
- if (isalpha(*system))
- goto notnumber;
- /*
- * System name is really a phone number...
- * Copy the number then stomp on the original (in case the number
- * is private, we don't want 'ps' or 'w' to find it).
- */
- if (strlen(system) > sizeof PNbuf - 1) {
- fprintf(stderr, "tip: phone number too long (max = %d bytes)\n",
- sizeof PNbuf - 1);
- exit(1);
- }
- strncpy( PNbuf, system, sizeof PNbuf - 1 );
- for (p = system; *p; p++)
- *p = '\0';
- PN = PNbuf;
- (void)sprintf(sbuf, "tip%d", BR);
- system = sbuf;
-
- notnumber:
- signal(SIGINT, cleanup);
- signal(SIGQUIT, cleanup);
- signal(SIGHUP, cleanup);
- signal(SIGTERM, cleanup);
- signal(SIGPIPE, cleanup);
-
- if ((i = hunt(system)) == 0) {
- printf("all ports busy\n");
- exit(3);
- }
- if (i == -1) {
- printf("link down\n");
- (void)uu_unlock(uucplock);
- exit(3);
- }
- setbuf(stdout, NULL);
- loginit();
-
- /*
- * Kludge, their's no easy way to get the initialization
- * in the right order, so force it here
- */
- if ((PH = getenv("PHONES")) == NOSTR)
- PH = "/etc/phones";
- vinit(); /* init variables */
- setparity("none"); /* set the parity table */
- if ((i = speed(number(value(BAUDRATE)))) == NULL) {
- printf("tip: bad baud rate %d\n", number(value(BAUDRATE)));
- (void)uu_unlock(uucplock);
- exit(3);
- }
-
- if (slip) {
- if (SA == NOSTR) {
- printf("tip: local addr not set\n");
- uu_unlock(uucplock);
- exit(3);
- }
- if (DA == NOSTR) {
- printf("tip: destination addr not set\n");
- uu_unlock(uucplock);
- exit(3);
- }
- if (SM == NOSTR) {
- printf("tip: slip netmask not set\n");
- uu_unlock(uucplock);
- exit(3);
- }
- }
-
- /*
- * Now that we have the logfile and the ACU open
- * return to the real uid and gid. These things will
- * be closed on exit. Swap real and effective uid's
- * so we can get the original permissions back
- * for removing the uucp lock.
- */
- user_uid(); /* in the case of slip, we are now priviliged */
-
- /*
- * Hardwired connections require the
- * line speed set before they make any transmissions
- * (this is particularly true of things like a DF03-AC)
- */
- if (HW)
- ttysetup(i);
- if (p = lconnect()) {
- printf("\07%s\n[EOT]\n", p);
- daemon_uid();
- (void)uu_unlock(uucplock);
- exit(1);
- }
- if (!HW)
- ttysetup(i);
-
-
- if (LS != NOSTR) {
- fprintf(stderr, "\07[Logging in...]\r\n");
- if (p = login()) {
- printf("\07%s\n[EOT]\n", p);
- daemon_uid();
- (void)uu_unlock(uucplock);
- exit(1);
- }
- }
-
- if (page) {
- i = sendpage(data);
- daemon_uid();
- (void)uu_unlock(uucplock);
- exit(i);
- }
-
- if (slip) {
- i = runslip();
- daemon_uid();
- (void)uu_unlock(uucplock);
- exit(i);
- }
-
- cucommon:
- /*
- * From here down the code is shared with
- * the "cu" version of tip.
- */
-
- ioctl(0, TIOCGETP, (char *)&defarg);
- ioctl(0, TIOCGETC, (char *)&defchars);
- ioctl(0, TIOCGLTC, (char *)&deflchars);
- ioctl(0, TIOCGETD, (char *)&odisc);
- arg = defarg;
- arg.sg_flags = ANYP | CBREAK;
- tchars = defchars;
- tchars.t_intrc = tchars.t_quitc = -1;
- ltchars = deflchars;
- ltchars.t_suspc = ltchars.t_dsuspc = ltchars.t_flushc
- = ltchars.t_lnextc = -1;
- raw();
-
- pipe(fildes); pipe(repdes);
- signal(SIGALRM, timeout);
-
- /*
- * Everything's set up now:
- * connection established (hardwired or dialup)
- * line conditioned (baud rate, mode, etc.)
- * internal data structures (variables)
- * so, fork one process for local side and one for remote.
- */
- printf(cumode ? "Connected\r\n" : "\07connected\r\n");
- if (pid = fork())
- tipin();
- else
- tipout();
- /*NOTREACHED*/
- }
-
- sigfunc_t
- cleanup()
- {
-
- daemon_uid();
- (void)uu_unlock(uucplock);
- if (pid) {
- (void) kill(pid, SIGTERM);
- unraw();
- } else if (odisc)
- ioctl(0, TIOCSETD, (char *)&odisc);
- exit(0);
- }
-
- /*
- * Muck with user ID's. We are setuid to the owner of the lock
- * directory when we start. user_uid() reverses real and effective
- * ID's after startup, to run with the user's permissions.
- * daemon_uid() switches back to the privileged uid for unlocking.
- * Finally, to avoid running a shell with the wrong real uid,
- * shell_uid() sets real and effective uid's to the user's real ID.
- */
- static int uidswapped;
-
- user_uid()
- {
- if (uidswapped == 0) {
- setregid(egid, gid);
- setreuid(euid, uid);
- uidswapped = 1;
- }
- }
-
- daemon_uid()
- {
- if (uidswapped) {
- setreuid(uid, euid);
- setregid(gid, egid);
- uidswapped = 0;
- }
- }
-
- shell_uid()
- {
-
- setreuid(uid, uid);
- setregid(gid, gid);
- }
-
- /*
- * put the controlling keyboard into raw mode
- */
- raw()
- {
-
- ioctl(0, TIOCSETP, &arg);
- ioctl(0, TIOCSETC, &tchars);
- ioctl(0, TIOCSLTC, <chars);
- ioctl(0, TIOCSETD, (char *)&disc);
- }
-
-
- /*
- * return keyboard to normal mode
- */
- unraw()
- {
-
- ioctl(0, TIOCSETD, (char *)&odisc);
- ioctl(0, TIOCSETP, (char *)&defarg);
- ioctl(0, TIOCSETC, (char *)&defchars);
- ioctl(0, TIOCSLTC, (char *)&deflchars);
- }
-
- static jmp_buf promptbuf;
-
- /*
- * Print string ``s'', then read a string
- * in from the terminal. Handles signals & allows use of
- * normal erase and kill characters.
- */
- prompt(s, p)
- char *s;
- register char *p;
- {
- register char *b = p;
- sigfunc_t (*oint)(), (*oquit)();
-
- stoprompt = 0;
- oint = signal(SIGINT, intprompt);
- oquit = signal(SIGQUIT, SIG_IGN);
- unraw();
- printf("%s", s);
- if (setjmp(promptbuf) == 0)
- while ((*p = getchar()) != EOF && *p != '\n')
- p++;
- *p = '\0';
-
- raw();
- signal(SIGINT, oint);
- signal(SIGQUIT, oint);
- return (stoprompt || p == b);
- }
-
- /*
- * Interrupt service routine during prompting
- */
- sigfunc_t
- intprompt()
- {
-
- signal(SIGINT, SIG_IGN);
- stoprompt = 1;
- printf("\r\n");
- longjmp(promptbuf, 1);
- }
-
- /*
- * ****TIPIN TIPIN****
- */
- tipin()
- {
- char gch, bol = 1;
-
- /*
- * Kinda klugey here...
- * check for scripting being turned on from the .tiprc file,
- * but be careful about just using setscript(), as we may
- * send a SIGEMT before tipout has a chance to set up catching
- * it; so wait a second, then setscript()
- */
- if (boolean(value(SCRIPT))) {
- sleep(1);
- setscript();
- }
-
- while (1) {
- gch = getchar()&0177;
- if ((gch == character(value(ESCAPE))) && bol) {
- if (!(gch = escape()))
- continue;
- } else if (!cumode && gch == character(value(RAISECHAR))) {
- boolean(value(RAISE)) = !boolean(value(RAISE));
- continue;
- } else if (gch == '\r') {
- bol = 1;
- pwrite(FD, &gch, 1);
- if (boolean(value(HALFDUPLEX)))
- printf("\r\n");
- continue;
- } else if (!cumode && gch == character(value(FORCE)))
- gch = getchar()&0177;
- bol = any(gch, value(EOL));
- if (boolean(value(RAISE)) && islower(gch))
- gch = toupper(gch);
- pwrite(FD, &gch, 1);
- if (boolean(value(HALFDUPLEX)))
- printf("%c", gch);
- }
- }
-
- /*
- * Escape handler --
- * called on recognition of ``escapec'' at the beginning of a line
- */
- escape()
- {
- register char gch;
- register esctable_t *p;
- char c = character(value(ESCAPE));
- extern esctable_t etable[];
-
- gch = (getchar()&0177);
- for (p = etable; p->e_char; p++)
- if (p->e_char == gch) {
- if ((p->e_flags&PRIV) && uid)
- continue;
- printf("%s", ctrl(c));
- (*p->e_func)(gch);
- return (0);
- }
- /* ESCAPE ESCAPE forces ESCAPE */
- if (c != gch)
- pwrite(FD, &c, 1);
- return (gch);
- }
-
- speed(n)
- int n;
- {
- register int *p;
-
- for (p = bauds; *p != -1; p++)
- if (*p == n)
- return (p - bauds);
- return (NULL);
- }
-
- any(c, p)
- register char c, *p;
- {
- while (p && *p)
- if (*p++ == c)
- return (1);
- return (0);
- }
-
- size(s)
- register char *s;
- {
- register int i = 0;
-
- while (s && *s++)
- i++;
- return (i);
- }
-
- char *
- interp(s)
- register char *s;
- {
- static char buf[256];
- register char *p = buf, c, *q;
-
- while (c = *s++) {
- for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
- if (*q++ == c) {
- *p++ = '\\'; *p++ = *q;
- goto next;
- }
- if (c < 040) {
- *p++ = '^'; *p++ = c + 'A'-1;
- } else if (c == 0177) {
- *p++ = '^'; *p++ = '?';
- } else
- *p++ = c;
- next:
- ;
- }
- *p = '\0';
- return (buf);
- }
-
- char *
- ctrl(c)
- char c;
- {
- static char s[3];
-
- if (c < 040 || c == 0177) {
- s[0] = '^';
- s[1] = c == 0177 ? '?' : c+'A'-1;
- s[2] = '\0';
- } else {
- s[0] = c;
- s[1] = '\0';
- }
- return (s);
- }
-
- /*
- * Help command
- */
- help(c)
- char c;
- {
- register esctable_t *p;
- extern esctable_t etable[];
-
- printf("%c\r\n", c);
- for (p = etable; p->e_char; p++) {
- if ((p->e_flags&PRIV) && uid)
- continue;
- printf("%2s", ctrl(character(value(ESCAPE))));
- printf("%-2s %c %s\r\n", ctrl(p->e_char),
- p->e_flags&EXP ? '*': ' ', p->e_help);
- }
- }
-
- /*
- * Set up the "remote" tty's state
- */
- ttysetup(speed)
- int speed;
- {
- unsigned bits = LDECCTQ;
-
- arg.sg_ispeed = arg.sg_ospeed = speed;
- arg.sg_flags = RAW;
- if (boolean(value(TAND)))
- arg.sg_flags |= TANDEM;
- if (boolean(value(DTRHUP))) {
- ioctl(FD, TIOCSDTR, 0);
- ioctl(FD, TIOCHPCL, 0);
- }
- ioctl(FD, TIOCSETP, (char *)&arg);
- ioctl(FD, TIOCLBIS, (char *)&bits);
- }
-
- /*
- * Return "simple" name from a file name,
- * strip leading directories.
- */
- char *
- sname(s)
- register char *s;
- {
- register char *p = s;
-
- while (*s)
- if (*s++ == '/')
- p = s;
- return (p);
- }
-
- static char partab[0200];
-
- /*
- * Do a write to the remote machine with the correct parity.
- * We are doing 8 bit wide output, so we just generate a character
- * with the right parity and output it.
- */
- pwrite(fd, buf, n)
- int fd;
- char *buf;
- register int n;
- {
- register int i;
- register char *bp;
- extern int errno;
-
- bp = buf;
- for (i = 0; i < n; i++) {
- *bp = partab[(*bp) & 0177];
- bp++;
- }
- if (write(fd, buf, n) < 0) {
- if (errno == EIO)
- abort("Lost carrier.");
- /* this is questionable */
- perror("write");
- }
- }
-
- /*
- * Build a parity table with appropriate high-order bit.
- */
- setparity(defparity)
- char *defparity;
- {
- register int i;
- char *parity;
- extern char evenpartab[];
-
- if (value(PARITY) == NOSTR)
- value(PARITY) = defparity;
- parity = value(PARITY);
- for (i = 0; i < 0200; i++)
- partab[i] = evenpartab[i];
- if (equal(parity, "even"))
- return;
- if (equal(parity, "odd")) {
- for (i = 0; i < 0200; i++)
- partab[i] ^= 0200; /* reverse bit 7 */
- return;
- }
- if (equal(parity, "none") || equal(parity, "zero")) {
- for (i = 0; i < 0200; i++)
- partab[i] &= ~0200; /* turn off bit 7 */
- return;
- }
- if (equal(parity, "one")) {
- for (i = 0; i < 0200; i++)
- partab[i] |= 0200; /* turn on bit 7 */
- return;
- }
- fprintf(stderr, "%s: unknown parity value\n", PA);
- fflush(stderr);
- }
-
- /* The uid could be determined by stat()-ing ACULOG */
- getuucpuid()
- {
- struct passwd *pw;
-
- if ((pw = getpwnam("uucp")) == NULL) {
- fprintf(stderr, "tip: unable to get uucp uid\n");
- exit(1);
- }
- return(pw->pw_uid);
- }
-